背景
当我们需要为后端服务的访问进行鉴权,尤其是为一些自身不带鉴权且难以为其本身添加权限校验代码时,比如Kubernetes封装的docker容器登陆服务与前端结合的这类Web伪Terminal、再比如Kubeflow Jupyter Notebook这类WebIDE,往往需要一个组件充当Gateway用以判断请求是否能转发到后端或是将其拒绝。
在此背景下,通常已经有完整的鉴权服务器,需要做的只是将鉴权服务器与后端服务结合起来。
选型
Gateway App
首先,当然可以自己写一个Gateway,接收所有的请求后,调用鉴权服务,并决定放行与否。
但这种方案需要考虑开发和维护的时间成本及难度、以及性能问题。
Proxy
常见的代理有Haproxy及Nginx,其中Nginx的子请求模块(auth_request module)可以在请求转发前发起子请求,因此在上述应用场景中可以作为简捷的Gateway。
反向代理
架构
当Nginx接收到用户请求时,首先利用收集到的用户信息向鉴权服务器发起鉴权子请求,根据鉴权服务器的返回结果:
- 如果响应代码为20X,则转发到真实的后台服务,同时可带上从鉴权服务器获取的一些信息。
- 如果响应代码为401或403,以对应的代码拒绝客户端的请求。
- 如果是其他代码,则视为后端错误。
基本流程如下图所示:
时序如下图所示:
配置实例 - Kubeflow Jupyter Notebook
Kubeflow Jupyter Notebook是一种机器学习的WebIDE,通过Jupyter Hub生成,外界通过Websocket接口与其交互。
在Kubernetes环境中,如果对集群外(如浏览器)提供访问,可以通过NodePort的方式对外暴露其宿主机IP及端口,同时根据其namespace及名称来访问,如:1
2http://<Node的IP>:<NodePort>/notebook/<notebook所在的namespace名称>/<notebook名称>
e.g. http://www.example.com/notebook/test-namespace/test-notebook
但这种方式每个Notebook都需要占用一个Node端口,较为耗费端口资源。
而如果通过Nginx作为Gateway的方式来对外提供服务,只需暴露Node的一个Nginx Service端口,即可处理全部请求;Nginx Pod鉴权通过后再根据请求的参数及Notebook的内部地址(ClusterIP+端口)转发请求。
Nginx的配置如下:
鉴权服务器定义
指定鉴权服务器的地址,需要确保Nginx能访问的地址,如果鉴权服务在Kubernetes集群外部则需保证网络路由能到达,如果在内部则需有对应Service对集群内提供ClusterIP的访问方式。1
2
3upstream authserver {
server <addess of auth server>:<port>
}
主请求定义
1 | server{ |
子请求定义
1 | server { |
其他部分
1 | server { |
完整定义
1 | upstream authserver { |
另外需要注意的是,Nginx的默认模块中不包含该模块,因此需要--with-http_auth_request_module
参数,可以自己编译nginx镜像,也可以用此镜像:1
docker pull alterway/nginx:1.10-auth-request
参考资料
Module ngx_http_auth_request
Docker hub Image: Nginx with auth_request